package com.example.demo.dao;

import com.example.demo.config.error.BizException;
import com.example.demo.entity.*;
import com.example.demo.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: WinstonDeng
 * @Description:
 * @Date: Created in 10:19 2020/4/9
 * @Modified by:
 */
@Repository
public class FlowDao {
    @Autowired
    private FlowMapper flowMapper;

    @Autowired
    private FlowStepMapper flowStepMapper;

    @Autowired
    private DepartmentStepMapper departmentStepMapper;

    @Autowired
    private DoctorMapper doctorMapper;

    @Autowired
    private PatientMapper patientMapper;

    @Autowired
    private StepMapper stepMapper;

    @Autowired
    private DoctorFlowMapper doctorFlowMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private QuestionnaireMapper questionnaireMapper;

    @Autowired
    private QuestionnaireRecordMapper questionnaireRecordMapper;

    public Flow getById(Long flowId) throws BizException{
        Flow flow = flowMapper.findById(flowId);
        if (flow == null){
            throw new BizException("404", "未找到 flow");
        }
        List<FlowStep> flowStepList = flowStepMapper.findByFlowId(flowId);
        int warningLevel = 0;
        for(FlowStep flowStep:flowStepList){
            Step step = stepMapper.findById(flowStep.getStepId());
            flowStep.setStep(step);
            flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
            QuestionnaireRecord questionnaireRecord = questionnaireRecordMapper.findByFlowStepId(flowStep.getId());
            if (questionnaireRecord != null) {
                flowStep.setQuestionScore(questionnaireRecord.getScore());
                // 计算当前最大预警级别
                Questionnaire questionnaire = questionnaireMapper.findById(step.getQuestionnaireId());
                flowStep.setBasicWarning(questionnaire.getBasicWarning());
                flowStep.setSeriousWarning(questionnaire.getSeriousWarning());
                int maxLevel;
                if (questionnaireRecord.getScore() > questionnaire.getSeriousWarning()) {
                    maxLevel = 100;
                } else if (questionnaireRecord.getScore() > questionnaire.getBasicWarning()) {
                    maxLevel = 50;
                } else {
                    maxLevel = 0;
                }
                if (maxLevel > warningLevel) {
                    warningLevel = maxLevel;
                }
            }
        }
        flow.setWarningScore(warningLevel);
        flowMapper.updateFlow(flow);
        flow.setFlowStepList(flowStepList);
        return flow;
    }

    public boolean updateFlow(Flow flow) throws BizException{
        return flowMapper.updateFlow(flow);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean insertFlow(long doctorId, long patientId) throws BizException{
        Doctor doctor = doctorMapper.findById(doctorId);
        Patient patient = patientMapper.findById(patientId);
        if (doctor == null){
            throw new BizException("404", "未找到 doctor");
        }
        if(patient == null){
            throw new BizException("404", "未找到 patient");
        }
        Flow flow = new Flow();
        flow.setDoctorId(doctorId);
        flow.setPatientId(patientId);
        flow.setFlowPatientName(patient.getRealName());
        flow.setState(Flow.STATE_DOING);
        flow.setDescription(Flow.DESCRIPTION_DEFAULT);
        flow.setCreateTime(new Timestamp(System.currentTimeMillis()));
        flow.setBedNum(Flow.BEDNUM_DEFAULT);
        flow.setHospNum(Flow.HOSPNUM_DEFAULT);
        flow.setTempleteId(0);
        if(!flowMapper.insertFlow(flow)){
            throw new BizException("500", "insert flow error");
        }

        long flowId = flow.getId();
        //insert main doctor as level1 flow doctor
        if(insertDoctorFlow(flowId,doctorId,DoctorFlow.DUTY_LEVEL1) == null){
            throw new BizException("500", "insert doctor flow error");
        }

        List<FlowStep> flowStepList = new ArrayList<FlowStep>();
        if(flowId > 0){
            List<DepartmentStep> departmentStepList = departmentStepMapper.findByDepartmentId(doctor.getDepartmentId());
            // 流程分模块新建
            for(DepartmentStep departmentStep:departmentStepList){
                boolean flag=false;
                for(Integer tmpId:Flow.BASE_STEPS){
                    if (tmpId == departmentStep.getStepId()){
                        flag=true;
                        break;
                    }
                }
                if(flag == false){
                    continue;
                }
                Step step = stepMapper.findById(departmentStep.getStepId());
                FlowStep flowStep = new FlowStep();
                flowStep.setFlowId(flowId);
                flowStep.setState(FlowStep.STATE_UNFINISH);
                flowStep.setStepId(step.getId());
                flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
                flowStep.setCreateTime(new Timestamp(System.currentTimeMillis()));
                // init first step state for doing
                if(departmentStep.getStepNum() == 1){
                    flowStep.setState(FlowStep.STATE_DOING);
                }
                if(!flowStepMapper.insertFlowStep(flowStep)){
                    throw new BizException("500", "flowStep insert error");
                }
                flowStepList.add(flowStep);
            }

            flow.setFlowStepList(flowStepList);
            return true;
        }else {
            return false;
        }
    }

    public boolean addSteps(long flowId, long templeteId) throws BizException{
        Flow flow = getById(flowId);
        List<Integer> tmpList;
        flow.setTempleteId(templeteId);
        flowMapper.updateFlow(flow);
        if (templeteId == 1){
            tmpList = Flow.TEMP_STEPS_1;
        }else if(templeteId == 2){
            tmpList = Flow.TEMP_STEPS_2;
        }
        else if(templeteId == 3){
            tmpList = Flow.TEMP_STEPS_3;
        }
        else{
            return false;
        }
        List<FlowStep> flowStepList= flow.getFlowStepList();
        for (Integer stepId:tmpList) {
            Step step = stepMapper.findById(stepId);
            FlowStep flowStep = new FlowStep();
            flowStep.setFlowId(flowId);
            flowStep.setState(FlowStep.STATE_UNFINISH);
            flowStep.setStepId(stepId);
            flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
            flowStep.setCreateTime(new Timestamp(System.currentTimeMillis()));
            if(!flowStepMapper.insertFlowStep(flowStep)){
                throw new BizException("500", "flowStep insert error");
            }
            flowStepList.add(flowStep);
        }
        flow.setFlowStepList(flowStepList);
        return true;
    }

    public DoctorFlow insertDoctorFlow(Long flowId, Long otherId, String duty) throws BizException{
        if(flowMapper.findById(flowId) == null){
            throw new BizException("404", "未找到 flow");
        }
        if(doctorMapper.findById(otherId) == null){
            throw new BizException("404", "未找到 other doctor");
        }
        // otherId doctor 存在性判断，若不存在则新建，否则更新duty
        List<DoctorFlow> doctorFlowList = doctorFlowMapper.findByFlowId(flowId);
        for(DoctorFlow doctorFlow:doctorFlowList){
            if(doctorFlow.getDoctorId() == otherId){
                doctorFlow.setDuty(duty);
                doctorFlowMapper.updateDoctorFlow(doctorFlow);
                return doctorFlow;
            }
        }
        DoctorFlow doctorFlow = new DoctorFlow();
        doctorFlow.setFlowId(flowId);
        doctorFlow.setDoctorId(otherId);
        doctorFlow.setDuty(duty);
        if(!doctorFlowMapper.insertDoctorFlow(doctorFlow)){
            throw new BizException("500", "insert doctor flow error");
        }
        return doctorFlow;


    }

    @Transactional(rollbackFor = Exception.class)
    public List<FlowStep> pushFlow(long flowId, long doctorId) throws BizException{
        List<FlowStep> flowStepList = flowStepMapper.findByFlowId(flowId);
        long doingStepId = -1;
        List<Integer> stepIdList=new ArrayList<>();
        for(Integer tmp:Flow.BASE_STEPS){
            stepIdList.add(tmp);
        }
        long templeteId = flowMapper.findById(flowId).getTempleteId();
        if(templeteId==1){
            stepIdList.addAll(Flow.TEMP_STEPS_1);
        }else if(templeteId==2){
            stepIdList.addAll(Flow.TEMP_STEPS_2);
        }
        else if(templeteId==3){
            stepIdList.addAll(Flow.TEMP_STEPS_3);
        }
        // find doing step, and update it
        for(FlowStep flowStep:flowStepList){
            if(flowStep.getState() == FlowStep.STATE_DOING){
                doingStepId = flowStep.getStepId();
                Step step = stepMapper.findById(flowStep.getStepId());
                // can not update doing questionnaire
                if(step.getQuestionnaireId() > 0){
                    throw new BizException("406", "病人正在填写，无法推进");
                }
                flowStep.setState(FlowStep.STATE_FINISH);
                flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
                flowStepMapper.updateFlowStep(flowStep);
                break;
            }
        }
        // if all state is 0
        if (doingStepId == -1){
            for(FlowStep flowStep:flowStepList){
                if(flowStep.getStepId() == stepIdList.get(0)){
                    Step step = stepMapper.findById(stepIdList.get(0));
                    flowStep.setState(FlowStep.STATE_DOING);
                    flowStepMapper.updateFlowStep(flowStep);
                    flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
                    break;
                }
        }
        }else if(doingStepId == stepIdList.get(stepIdList.size()-1)){
            // if last one
            Flow flow = flowMapper.findById(flowId);
            flow.setState(Flow.STATE_FINISH);
            flowMapper.updateFlow(flow);
            return getById(flowId).getFlowStepList();
        }else {
            // update next one
            for(int i=1;i<flowStepList.size();i++){
                FlowStep flowStep = flowStepList.get(i);
                long curStepId = flowStep.getStepId();
                if(flowStep.getState() == FlowStep.STATE_UNFINISH){
                    Step step = stepMapper.findById(curStepId);
                    flowStep.setState(FlowStep.STATE_DOING);
                    flowStepMapper.updateFlowStep(flowStep);
                    flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
                    break;
                }
            }
        }
        return getById(flowId).getFlowStepList();
    }

//    @Transactional(rollbackFor = Exception.class)
//    public List<FlowStep> pushFlow(long flowId, long doctorId) throws BizException{
//       List<FlowStep> flowStepList = flowStepMapper.findByFlowId(flowId);
//       long departmentId = doctorMapper.findById(doctorId).getDepartmentId();
//       int doingOrderNum = -1;
//       int maxOrderNum = 0;
//       // find max order num
//       for(FlowStep flowStep:flowStepList){
//            DepartmentStep departmentStep = departmentStepMapper.findByDepartmentIdAndStepId(departmentId, flowStep.getStepId());
//            if(departmentStep.getStepNum() > maxOrderNum){
//                maxOrderNum = departmentStep.getStepNum();
//            }
//       }
//       // find doing step, and update it
//       for(FlowStep flowStep:flowStepList){
//           DepartmentStep departmentStep = departmentStepMapper.findByDepartmentIdAndStepId(departmentId, flowStep.getStepId());
//           if(flowStep.getState() == FlowStep.STATE_DOING){
//               doingOrderNum = departmentStep.getStepNum();
//               Step step = stepMapper.findById(flowStep.getStepId());
//               // can not update doing questionnaire
//               if(step.getQuestionnaireId() > 0){
//                   throw new BizException("406", "病人正在填写，无法推进");
//               }
//               flowStep.setState(FlowStep.STATE_FINISH);
//               flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
//               flowStepMapper.updateFlowStep(flowStep);
//               break;
//           }
//       }
//       // if all state is 0
//        if (doingOrderNum == -1){
//            for(FlowStep flowStep:flowStepList){
//                DepartmentStep departmentStep = departmentStepMapper.findByDepartmentIdAndStepId(departmentId, flowStep.getStepId());
//                if(departmentStep.getStepNum() == 1 ){
//                    Step step = stepMapper.findById(flowStep.getStepId());
//                    flowStep.setState(FlowStep.STATE_DOING);
//                    flowStepMapper.updateFlowStep(flowStep);
//                    flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
//                    break;
//                }
//            }
//        }else if(doingOrderNum == maxOrderNum){
//            // if last one
//           Flow flow = flowMapper.findById(flowId);
//           flow.setState(Flow.STATE_FINISH);
//           flowMapper.updateFlow(flow);
//           return getById(flowId).getFlowStepList();
//       }else {
//           // update next one
//           for(FlowStep flowStep:flowStepList){
//               DepartmentStep departmentStep = departmentStepMapper.findByDepartmentIdAndStepId(departmentId, flowStep.getStepId());
//               if(departmentStep.getStepNum() == doingOrderNum + 1 ){
//                   Step step = stepMapper.findById(flowStep.getStepId());
//                   flowStep.setState(FlowStep.STATE_DOING);
//                   flowStepMapper.updateFlowStep(flowStep);
//                   flowStep.setType(step.getQuestionnaireId()>0? FlowStep.TYPE_PATIENT: FlowStep.TYPE_DOCTOR);
//                   break;
//               }
//           }
//       }
//       return getById(flowId).getFlowStepList();
//    }

    public List<Flow> getListByDoctorIdAndState(long doctorId, int state) throws BizException{
        return flowMapper.findByDoctorIdAndState(doctorId, state);
    }

    public List<Flow> getListByPatientIdAndState(long patientId, int state) throws BizException{
        return flowMapper.findByPatientIdAndState(patientId, state);
    }

    public List<DoctorFlow> getFlowDoctorListByFlowId(long flowId) throws BizException{
        return doctorFlowMapper.findByFlowId(flowId);
    }

    public boolean shutDownFlow(long flowId) throws BizException{
        Flow flow = flowMapper.findById(flowId);
        if (flow == null){
            throw new BizException("404", "未找到 flow");
        }
        flow.setState(Flow.STATE_BREAK);
        return flowMapper.updateFlow(flow);
    }

    public Integer updateFlowScore(long flowId) throws BizException{
        Flow flow = flowMapper.findById(flowId);
        List<FlowStep> flowStepList = flowStepMapper.findByFlowId(flowId);
        int score = 0;
        int questionnaireNum = 0;
        for (FlowStep flowStep : flowStepList) {
            QuestionnaireRecord questionnaireRecord = questionnaireRecordMapper.findByFlowStepId(flowStep.getId());
            if (questionnaireRecord != null) {
                questionnaireNum++;
                score += questionnaireRecord.getScore();
            }
        }
        // 流程分数简单加权，除以问卷数量
        score /= questionnaireNum;
        flow.setWarningScore(score);
        flowMapper.updateFlow(flow);
        return score;
    }

}
